<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>08_Reflect-Reflect和construct结合反射</title>
  <!-- 
  在 JavaScript 中， `Reflect`  是一个内置对象，提供了一些方法用于操作对象的基本操作。 `Reflect.construct()`  方法用于创建对象的实例，结合构造函数和  `new`  操作符的功能。
  1.  `Reflect.construct()`  的基本概念
  -  `Reflect.construct(target, argumentsList[, newTarget])` ：
    -  `target` ：要调用的构造函数。
    -  `argumentsList` ：一个数组或类数组对象，包含传递给构造函数的参数。
    -  `newTarget` （可选）：如果提供，则用于创建实例的构造函数。通常用于继承。

  2. 主要用途
  `Reflect.construct()`  的主要用途是简化构造函数的调用，特别是在需要动态创建对象或实现继承时。

  3. 示例代码
  以下是一个使用  `Reflect.construct()`  的示例：
  function Person(name, age) {
      this.name = name;
      this.age = age;
  }

  const args = ["Alice", 30];

  // 使用 Reflect.construct 创建实例
  const alice = Reflect.construct(Person, args);

  console.log(alice.name); // 输出: Alice
  console.log(alice.age);  // 输出: 30
  在这个示例中， `Reflect.construct()`  被用来调用  `Person`  构造函数，并传递参数  `["Alice", 30]` ，最终创建了一个  `Person`  实例。

  4. 结合  `new`  操作符
  `Reflect.construct()`  还可以用于实现继承，特别是在子类中调用父类构造函数时。可以通过提供  `newTarget`  参数来实现。

  class Animal {
      constructor(name) {
          this.name = name;
      }
  }

  class Dog extends Animal {
      constructor(name, breed) {
          // 使用 Reflect.construct 调用父类构造函数
          super(name); // 传统方式
          this.breed = breed;
      }
  }

  const myDog = new Dog("Buddy", "Golden Retriever");
  console.log(myDog.name);  // 输出: Buddy
  console.log(myDog.breed); // 输出: Golden Retriever
  在这个示例中， `super(name)`  是使用传统方式调用父类构造函数。使用  `Reflect.construct()`  可以实现类似的效果，尤其是在更复杂的继承结构中。

  5. 反射与代理的结合
  `Reflect.construct()`  也可以与  `Proxy`  结合使用，以实现更复杂的对象创建逻辑。例如，可以在代理中拦截构造函数的调用。
  const handler = {
      construct(target, args) {
          console.log(`Creating instance of ${target.name} with arguments: ${args}`);
          return Reflect.construct(target, args);
      }
  };

  const ProxyPerson = new Proxy(Person, handler);
  const bob = new ProxyPerson("Bob", 25);
  // 输出: Creating instance of Person with arguments: Bob,25
  console.log(bob.name); // 输出: Bob
  在这个示例中，使用  `Proxy`  拦截了对  `Person`  构造函数的调用，并在创建实例之前输出了一条日志。

  6. 总结
  `Reflect.construct()`  是 JavaScript 中一个强大的方法，用于创建对象的实例，尤其在动态创建对象和实现继承时非常有用。它的主要优点在于简化了构造函数的调用，并提供了更灵活的方式来处理构造函数的参数和继承关系。在与  `Proxy`  结合使用时，可以实现更复杂的对象创建逻辑，增强了代码的灵活性和可维护性。理解  `Reflect.construct()`  的使用对于掌握 JavaScript 的面向对象编程和反射机制非常重要。
  -->
</head>
<body>

  <script>
    function Person(name, age) {
      this.name = name;
      this.age = age;
    }

    // 1. 使用 Reflect.construct() 创建实例
    function Student(name, age, grade) {
      // Person.call(this, name, age);
      this.grade = grade;
      const _this = Reflect.construct(Person, [name, age], Student);
      const res = Object.setPrototypeOf({..._this, ...this}, Student.prototype);
      return res;
    }

    const stu = new Student("Bob", 25, 3);
    console.log(stu);
    console.log(stu.name, stu.age, stu.grade); // 输出: Bob, 25, 3
    console.log(stu.__proto__ === Student.prototype); // 输出: true
    
    // 2. 使用 Proxy 和 Reflect 实现自定义的构造函数
    const proxyConstructor = new Proxy(Person, {
      construct(target, args, newTarget) {
        console.log(`Creating an instance of ${target.name} with arguments: ${args}`);
        return new target(...args);
      }
    });

    const bob = new proxyConstructor("proxyConstructor", 35);
    console.log(bob);



  </script>
  
</body>
</html>